﻿using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Globalization;

using Storm.TextEditor.Core;
using Storm.TextEditor.Drawing.GDI;
using Storm.TextEditor.Editor;
using Storm.TextEditor.Editor.Text;
using Storm.TextEditor.Parser.Objects;
using Storm.TextEditor.Parser.Objects.Collections;

namespace Storm.TextEditor.Drawing
{
    /// <summary>
    /// Represents a painter that paints a TextEditorBase.
    /// </summary>
    public class DefaultPainter
        : IPainter
    {
        #region Fields

        private int firstSpanRow = 0;
        private int lastSpanRow = 0;

        private int lastRow = 0;
        private int yOffset = 0;
        private int resizeCount = 0;

        private bool spanFound = false;
        private bool renderCaretRowOnly = false;

        private TextEditorBase textEditorControl = null;
        private RenderItems renderItems = new RenderItems();

        private Word bracketStart = null;
        private Word bracketEnd = null;

        private Graphics currentGraphics = null;

        #region Events

        /// <summary>
        /// Occurs when the default margins (gutter margin and line number margin) are being rendered.
        /// </summary>
        public event RenderMarginEventHandler RenderDefaultMargins;

        #endregion

        #endregion

        #region Methods

        #region Public

        /// <summary>
        /// Handles the Resize event of the parent TextEditorBase, reinitializes the graphics of the DefaultPainter.
        /// </summary>
        public void Resize()
        {
            resizeCount++;
            this.InitGraphics();
        }

        /// <summary>
        /// Measures the given string and returns the size of it.
        /// </summary>
        /// <param name="measureString">String to measure.</param>
        /// <returns>The found size.</returns>
        public Size MeasureString(string measureString)
        {
            renderItems.StringBuffer.Font = renderItems.FontNormal;
            return renderItems.StringBuffer.MeasureTabbedString(measureString, textEditorControl.TabSpaces);
        }

        /// <summary>
        /// Initializes GDI32 backbuffers and brushes.
        /// </summary>
        public void InitGraphics()
        {
            if (renderItems.BackgroundBrush != null)
                renderItems.BackgroundBrush.Dispose();

            if (renderItems.GutterMarginBrush != null)
                renderItems.GutterMarginBrush.Dispose();

            if (renderItems.LineNumberMarginBrush != null)
                renderItems.LineNumberMarginBrush.Dispose();

            if (renderItems.HighlightLineBrush != null)
                renderItems.HighlightLineBrush.Dispose();

            if (renderItems.LineNumberMarginBorderBrush != null)
                renderItems.LineNumberMarginBorderBrush.Dispose();

            if (renderItems.GutterMarginBorderBrush != null)
                renderItems.GutterMarginBorderBrush.Dispose();

            if (renderItems.OutlineBrush != null)
                renderItems.OutlineBrush.Dispose();

            renderItems.BackgroundBrush = new GDIBrush(textEditorControl.BackColor);
            renderItems.GutterMarginBrush = new GDIBrush(textEditorControl.GutterMarginColor);
            renderItems.LineNumberMarginBrush = new GDIBrush(textEditorControl.LineNumberBackColor);
            renderItems.HighlightLineBrush = new GDIBrush(textEditorControl.HighlightedLineColor);
            renderItems.LineNumberMarginBorderBrush = new GDIBrush(textEditorControl.LineNumberBorderColor);
            renderItems.OutlineBrush = new GDIBrush(textEditorControl.OutlineColor);
            renderItems.CollapsedBackgroundBrush = new GDIBrush(textEditorControl.CollapsedBackgroundColor);
            renderItems.SymbolBrush = new GDIBrush(textEditorControl.ExpansionSymbolColor);
            renderItems.ExpansionBackgroundBrush = new GDIBrush(textEditorControl.ExpansionBackgroundColor);

            if (renderItems.FontNormal != null)
                renderItems.FontNormal.Dispose();

            if (renderItems.FontBold != null)
                renderItems.FontBold.Dispose();

            if (renderItems.FontItalic != null)
                renderItems.FontItalic.Dispose();

            if (renderItems.FontBoldItalic != null)
                renderItems.FontBoldItalic.Dispose();

            if (renderItems.FontUnderline != null)
                renderItems.FontUnderline.Dispose();

            if (renderItems.FontBoldUnderline != null)
                renderItems.FontBoldUnderline.Dispose();

            if (renderItems.FontItalicUnderline != null)
                renderItems.FontItalicUnderline.Dispose();

            if (renderItems.FontBoldItalicUnderline != null)
                renderItems.FontBoldItalicUnderline.Dispose();

            string font = textEditorControl.FontName;
            float fontsize = textEditorControl.FontSize;

            renderItems.FontNormal = new GDIFont(font, fontsize, false, false, false, false);
            renderItems.FontBold = new GDIFont(font, fontsize, true, false, false, false);
            renderItems.FontItalic = new GDIFont(font, fontsize, false, true, false, false);
            renderItems.FontBoldItalic = new GDIFont(font, fontsize, true, true, false, false);
            renderItems.FontUnderline = new GDIFont(font, fontsize, false, false, true, false);
            renderItems.FontBoldUnderline = new GDIFont(font, fontsize, true, false, true, false);
            renderItems.FontItalicUnderline = new GDIFont(font, fontsize, false, true, true, false);
            renderItems.FontBoldItalicUnderline = new GDIFont(font, fontsize, true, true, true, false);

            this.InitIMEWindow();
            if (textEditorControl != null)
            {
                if (textEditorControl.IsHandleCreated == true)
                {
                    if (renderItems.StringBuffer != null)
                        renderItems.StringBuffer.Dispose();

                    if (renderItems.SelectionBuffer != null)
                        renderItems.SelectionBuffer.Dispose();

                    if (renderItems.BackBuffer != null)
                        renderItems.BackBuffer.Dispose();

                    renderItems.StringBuffer = new GDISurface(1, 1, textEditorControl, true);
                    renderItems.StringBuffer.Font = renderItems.FontNormal;

                    int rowHeight = renderItems.StringBuffer.MeasureTabbedString("ABC", 0).Height + textEditorControl.TextEditor.RowPadding;
                    renderItems.BackBuffer = new GDISurface(textEditorControl.ClientWidth, rowHeight, textEditorControl, true);
                    renderItems.SelectionBuffer = new GDISurface(textEditorControl.ClientWidth, rowHeight, textEditorControl, true);

                    renderItems.BackBuffer.Font = renderItems.FontNormal;
                    renderItems.SelectionBuffer.Font = renderItems.FontNormal;

                    textEditorControl.ViewPoint.RowHeight = rowHeight;
                    textEditorControl.ViewPoint.CharWidth = renderItems.BackBuffer.MeasureTabbedString(" ", 0).Width;
                }
            }
        }

        /// <summary>
        /// Measures the given row and returns its size.
        /// </summary>
        /// <param name="measureRow">Row to measure.</param>
        /// <param name="paddingCharCount">Number of padding characters to use when creating and measuring the padding.</param>
        /// <returns>The size of the given row.</returns>
        public Size MeasureRow(Row measureRow, int paddingCharCount)
        {
            return this.MeasureRow(measureRow, paddingCharCount, 0);
        }

        /// <summary>
        /// Renders the caret of the TextEditor.
        /// </summary>
        /// <param name="g">Graphics to use when rendering.</param>
        public void RenderCaret(Graphics g)
        {
            renderCaretRowOnly = true;

            this.RenderAll(g);

            renderCaretRowOnly = false;
        }

        /// <summary>
        /// Renders all content of the TextEditor.
        /// </summary>
        public void RenderAll()
        {
            textEditorControl.ViewPoint.RowHeight = 0;
            textEditorControl.ViewPoint.CharWidth = 0;
            textEditorControl.SetupViewPoint();

            Graphics graphics = textEditorControl.CreateGraphics();
            graphics.SmoothingMode = SmoothingMode.AntiAlias;

            currentGraphics = graphics;
            this.RenderAll(graphics);
        }

        /// <summary>
        /// Renders all content of the TextEditor.
        /// </summary>
        /// <param name="g">Graphics to use when rendering.</param>
        public void RenderAll(Graphics g)
        {
            textEditorControl.SetupViewPoint();

            this.SetBrackets();
            this.SetSpanIndicators();

            int firstVisibleRow = textEditorControl.ViewPoint.FirstVisibleRow;

            int difference = firstVisibleRow - lastRow;
            lastRow = firstVisibleRow;

            if (textEditorControl.SmoothScroll == true)
            {
                if (difference == 1)
                {
                    for (int i = textEditorControl.ViewPoint.RowHeight; i > 0; i -= textEditorControl.SmoothScrollSpeed)
                    {
                        yOffset = i + textEditorControl.ViewPoint.YOffset;
                        this.RenderAllBase(g);

                        g.Flush();
                    }
                }
                else if (difference == -1)
                {
                    for (int i = -textEditorControl.ViewPoint.RowHeight; i < 0; i += textEditorControl.SmoothScrollSpeed)
                    {
                        yOffset = i + textEditorControl.ViewPoint.YOffset;
                        this.RenderAllBase(g);

                        g.Flush();
                    }
                }
            }

            yOffset = textEditorControl.ViewPoint.YOffset;
            this.RenderAllBase(g);
        }

        /// <summary>
        /// Renders the row at the given index.
        /// </summary>
        /// <param name="rowIndex">Index of the row to render.</param>
        public void RenderRow(int rowIndex)
        {
            RenderRow(rowIndex, 10);
        }

        /// <summary>
        /// Returns the Point at the given TextPoint.
        /// </summary>
        /// <param name="textPoint">TextPoint to find Point on.</param>
        /// <returns>The Point at the given TextPoint.</returns>
        public Point GetPixelAtTextPoint(TextPoint textPoint)
        {
            return this.GetTextPointPixelPos(textPoint);
        }

        /// <summary>
        /// Returns the TextPoint at the given coordinates.
        /// </summary>
        /// <param name="x">X coordinate to find TextPoint on.</param>
        /// <param name="y">Y coordinate to find TextPoint on.</param>
        /// <returns>The TextPoint at the given coordinates.</returns>
        public TextPoint GetTextPointAtPixel(int x, int y)
        {
            int rowIndex = y / textEditorControl.ViewPoint.RowHeight + textEditorControl.ViewPoint.FirstVisibleRow;
            rowIndex = Math.Min(rowIndex, textEditorControl.Document.VisibleRows.Count);

            Row row = null;
            if (rowIndex == textEditorControl.Document.VisibleRows.Count)
            {
                rowIndex--;
                row = textEditorControl.Document.VisibleRows[rowIndex];
                if (row.IsCollapsed == true)
                    row = row.ExpansionEndRow;

                return new TextPoint(row.Text.Length, row.Index);
            }

            rowIndex = Math.Max(rowIndex, 0);
            if (textEditorControl.Document.VisibleRows.Count != 0)
            {
                row = textEditorControl.Document.VisibleRows[rowIndex];
                rowIndex = textEditorControl.Document.IndexOf(row);
            }
            else
                return new TextPoint(0, 0);

            if (rowIndex == -1)
                return new TextPoint(-1, -1);

            if (row.IsCollapsed == false)
                return this.GetTextPointFromRowColumn(rowIndex, x);

            if (x < row.ExpansionPixelEnd - textEditorControl.ViewPoint.FirstVisibleColumn * textEditorControl.ViewPoint.CharWidth)
                return this.GetTextPointFromRowColumn(rowIndex, x);
            else if (x >= row.ExpansionEndRow.ExpansionPixelStart - textEditorControl.ViewPoint.FirstVisibleColumn *
                textEditorControl.ViewPoint.CharWidth + textEditorControl.ViewPoint.TextMargin)
            {
                return GetTextPointFromRowColumn(row.ExpansionEndRow.Index, x - row.ExpansionEndRow.ExpansionPixelStart + this.MeasureRow
                    (row.ExpansionEndRow, row.ExpansionEndRow.ExpansionStartChar, row.ExpansionEndRow.ExpansionPixelStart).Width);
            }
            else
                return new TextPoint(row.ExpansionEndChar, row.Index);
        }

        /// <summary>
        /// Returns the maximum character width.
        /// </summary>
        /// <returns>The maximum character width.</returns>
        public int GetMaxCharWidth()
        {
            string charTable = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
            int maximumWidth = 0;

            foreach (char character in charTable)
            {
                int characterWidth = this.MeasureString(character + "").Width;
                if (characterWidth > maximumWidth)
                    maximumWidth = characterWidth;
            }

            return maximumWidth;
        }

        /// <summary>
        /// Disposes the DefaultPainter and its children.
        /// </summary>
        public void Dispose()
        {
            renderItems.Dispose();
        }

        #endregion

        #region Private

        /// <summary>
        /// Renders a rectangle with the given width and height at the given coordinates.
        /// </summary>
        /// <param name="x">X coordinate to render the rectangle at.</param>
        /// <param name="y">Y coordinate to render the rectangle at.</param>
        /// <param name="width">Width of the rectangle.</param>
        /// <param name="height">Height of the rectangle</param>
        private void RenderRectangle(int x, int y, int width, int height)
        {
            renderItems.SelectionBuffer.RenderTo(renderItems.BackBuffer, x, y, width, height, x, y);
        }

        /// <summary>
        /// Sets the font of the given GDISurface to the given values.
        /// </summary>
        /// <param name="bold">Whether the font should be bold.</param>
        /// <param name="italic">Whether the font should be italic.</param>
        /// <param name="underline">Whether the font should be underlined.</param>
        /// <param name="backBuffer">GDISurface to set font of.</param>
        private void SetFont(bool bold, bool italic, bool underline, GDISurface backBuffer)
        {
            if (bold == true)
                if (italic == true)
                    if (underline == true)
                        backBuffer.Font = renderItems.FontBoldItalicUnderline;
                    else
                        backBuffer.Font = renderItems.FontBoldItalic;
                else if (underline == true)
                    backBuffer.Font = renderItems.FontBoldUnderline;
                else
                    backBuffer.Font = renderItems.FontBold;
            else if (italic == true)
                if (underline == true)
                    backBuffer.Font = renderItems.FontItalicUnderline;
                else
                    backBuffer.Font = renderItems.FontItalic;
            else if (underline == true)
                backBuffer.Font = renderItems.FontUnderline;
            else
                backBuffer.Font = renderItems.FontNormal;
        }

        /// <summary>
        /// Sets the font of the RenderItems' StringBuffer GDISurface to the given values.
        /// </summary>
        /// <param name="bold">Whether the font should be bold.</param>
        /// <param name="italic">Whether the font should be italic.</param>
        /// <param name="underline">Whether the font should be underlined.</param>
        private void SetStringFont(bool bold, bool italic, bool underline)
        {
            GDISurface backBuffer = renderItems.StringBuffer;
            if (bold == true)
                if (italic == true)
                    if (underline == true)
                        backBuffer.Font = renderItems.FontBoldItalicUnderline;
                    else
                        backBuffer.Font = renderItems.FontBoldItalic;
                else if (underline == true)
                    backBuffer.Font = renderItems.FontBoldUnderline;
                else
                    backBuffer.Font = renderItems.FontBold;
            else if (italic == true)
                if (underline == true)
                    backBuffer.Font = renderItems.FontItalicUnderline;
                else
                    backBuffer.Font = renderItems.FontItalic;
            else if (underline == true)
                backBuffer.Font = renderItems.FontUnderline;
            else
                backBuffer.Font = renderItems.FontNormal;
        }

        /// <summary>
        /// Updates the DefaultPainter's local bracket values to match the TextEditor's Caret's current word.
        /// </summary>
        private void SetBrackets()
        {
            Segment currentSegment = null;

            bracketEnd = null;
            bracketStart = null;

            Word currentWord = textEditorControl.Caret.CurrentWord;
            if (currentWord != null)
            {
                currentSegment = currentWord.Segment;
                if (currentSegment != null)
                {
                    if (currentWord == currentSegment.StartWord || currentWord == currentSegment.EndWord)
                    {
                        bracketEnd = currentSegment.EndWord;
                        bracketStart = currentSegment.StartWord;
                    }

                    if (currentWord == null || currentWord.Pattern == null)
                        return;

                    if (currentWord.Pattern.BracketType == BracketType.EndBracket)
                    {
                        if (currentWord.Segment.StartRow == null)
                            currentWord.Segment.StartRow = currentWord.Segment.StartWord.Row;

                        Word word = textEditorControl.Document.GetStartBracketWord(currentWord,
                            currentWord.Pattern.MatchingBracket, currentWord.Segment);

                        bracketEnd = currentWord;
                        bracketStart = word;
                    }
                    else if (currentWord.Pattern.BracketType == BracketType.StartBracket)
                    {
                        Word word = textEditorControl.Document.GetEndBracketWord(currentWord,
                            currentWord.Pattern.MatchingBracket, currentWord.Segment);

                        bracketEnd = word;
                        bracketStart = currentWord;
                    }
                }
            }
        }

        /// <summary>
        /// Sets the positions of the span indicators.
        /// </summary>
        private void SetSpanIndicators()
        {
            spanFound = false;
            Segment currentSegment = textEditorControl.Caret.CurrentSegment();

            if (currentSegment == null || currentSegment.StartWord == null || currentSegment.StartWord.Row == null ||
                currentSegment.EndWord == null || currentSegment.EndWord.Row == null)
            {
                return;
            }

            firstSpanRow = currentSegment.StartWord.Row.Index;
            lastSpanRow = currentSegment.EndWord.Row.Index;

            spanFound = true;
        }

        /// <summary>
        /// Initializes the IME Window of the TextEditor.
        /// </summary>
        private void InitIMEWindow()
        {
            if (textEditorControl.IMEWindow != null)
                textEditorControl.IMEWindow.SetFont(textEditorControl.FontName, textEditorControl.FontSize);
        }

        /// <summary>
        /// Measures the given row and returns its size.
        /// </summary>
        /// <param name="measureRow">Row to measure.</param>
        /// <param name="paddingCharCount">Number of padding characters to use when creating and measuring the padding.</param>
        /// <param name="xOffset">X coordinate to start at.</param>
        /// <returns>The size of the given row.</returns>
        private Size MeasureRow(Row measureRow, int paddingCharCount, int xOffset)
        {
            int width = 0;

            int xPos = textEditorControl.ViewPoint.TextMargin - textEditorControl.ViewPoint.ClientAreaStart;
            int maximumTextWidth = -textEditorControl.ViewPoint.FirstVisibleColumn * textEditorControl.ViewPoint.CharWidth +
                textEditorControl.ViewPoint.TextMargin;

            if (measureRow.InQueue == true)
            {
                this.SetStringFont(false, false, false);

                int padding = Math.Max(paddingCharCount - measureRow.Text.Length, 0);
                string paddingString = new string(' ', padding);

                string emptyText = measureRow.Text + paddingString;
                width = renderItems.StringBuffer.MeasureTabbedString(emptyText.Substring(0, paddingCharCount), textEditorControl.PixelTabSize).Width;
            }
            else
            {
                int charIndex = 0;
                int addedWidth = 0;
                int charPosition = 0;

                foreach (Word word in measureRow.FormattedWords)
                {
                    if (word.Type == WordType.Word && word.Style != null)
                        this.SetStringFont(word.Style.Bold, word.Style.Italic, word.Style.Underline);
                    else
                        this.SetStringFont(false, false, false);

                    if (word.Text.Length + charIndex >= paddingCharCount || word == measureRow.FormattedWords[measureRow.FormattedWords.Count - 1])
                    {
                        charPosition = paddingCharCount - charIndex;

                        int maximumCharacterPosition = Math.Min(charPosition, word.Text.Length);
                        if (maximumCharacterPosition < 0)
                            break;

                        addedWidth += renderItems.StringBuffer.DrawTabbedString(word.Text.Substring(0, maximumCharacterPosition), xPos +
                            addedWidth, 0, maximumTextWidth, textEditorControl.PixelTabSize).Width;

                        width = addedWidth;
                        break;
                    }
                    else
                    {
                        addedWidth += renderItems.StringBuffer.DrawTabbedString(word.Text, xPos + addedWidth, 0, maximumTextWidth,
                            textEditorControl.PixelTabSize).Width;

                        charIndex += word.Text.Length;
                    }
                }

                this.SetStringFont(false, false, false);

                int padding = Math.Max(paddingCharCount - measureRow.Text.Length, 0);
                string paddingString = new string(' ', padding);

                width += renderItems.StringBuffer.DrawTabbedString(paddingString, xPos + addedWidth, 0, maximumTextWidth,
                    textEditorControl.PixelTabSize).Width;
            }

            return new Size(width, 0);
        }

        /// <summary>
        /// Returns the TextPoint that is the closest to a character at the given y coordinate in the row at the given index.
        /// </summary>
        /// <param name="rowIndex">Index of the row.</param>
        /// <param name="y">Y of the TextPoint to find.</param>
        /// <returns>The TextPoint that is the closest to a character at the given y coordinate in the row at the given index.</returns>
        private TextPoint GetTextPointFromRowColumn(int rowIndex, int y)
        {
            Row row = textEditorControl.Document[rowIndex];
            int maximumCharIndex = row.Text.Length;

            y -= textEditorControl.ViewPoint.TextMargin - 2 - textEditorControl.ViewPoint.FirstVisibleColumn * textEditorControl.ViewPoint.CharWidth;

            if (row.Count == 0)
            {
                if (textEditorControl.VirtualWhitespace && textEditorControl.ViewPoint.CharWidth > 0)
                    return new TextPoint(y / textEditorControl.ViewPoint.CharWidth, rowIndex);
                else
                    return new TextPoint(0, rowIndex);
            }

            int tabOrigin = -textEditorControl.ViewPoint.FirstVisibleColumn * textEditorControl.ViewPoint.CharWidth + textEditorControl.ViewPoint.TextMargin;
            int x = textEditorControl.ViewPoint.TextMargin - textEditorControl.ViewPoint.ClientAreaStart;

            int charIndex = 0;
            int totalWidth = 0;

            Word lastWord = null;
            Word currentWord = null;

            int wordWidth = 0;
            WordCollection wordCollection = row.FormattedWords;

            for (int i = 0; i < wordCollection.Count; i++)
            {
                currentWord = wordCollection[i];

                lastWord = currentWord;
                wordWidth = totalWidth;

                if (currentWord.Type == WordType.Word && currentWord.Style != null)
                    this.SetStringFont(currentWord.Style.Bold, currentWord.Style.Italic, currentWord.Style.Underline);
                else
                    this.SetStringFont(false, false, false);

                int currentWordWidth = renderItems.StringBuffer.DrawTabbedString(currentWord.Text, x + totalWidth, 0, tabOrigin,
                    textEditorControl.PixelTabSize).Width;

                if (totalWidth + currentWordWidth >= y)
                    break;

                if (currentWord != row.FormattedWords[row.FormattedWords.Count - 1])
                {
                    totalWidth += currentWordWidth;
                    charIndex += currentWord.Text.Length;
                }
            }

            if (lastWord.Type == WordType.Word && lastWord.Style != null)
                this.SetStringFont(lastWord.Style.Bold, lastWord.Style.Italic, lastWord.Style.Underline);
            else
                this.SetStringFont(false, false, false);

            bool foundCharacter = false;
            foreach (char character in lastWord.Text)
            {
                int characterWidth = renderItems.StringBuffer.DrawTabbedString(character + "", x + wordWidth, 0, tabOrigin,
                    textEditorControl.PixelTabSize).Width;

                if (wordWidth + characterWidth >= y)
                {
                    foundCharacter = true;
                    break;
                }

                charIndex++;
                wordWidth += characterWidth;
            }

            if (foundCharacter == false && textEditorControl.ViewPoint.CharWidth > 0 && textEditorControl.VirtualWhitespace == true)
            {
                int newY = y - wordWidth;
                int actualY = newY / textEditorControl.ViewPoint.CharWidth;

                charIndex += actualY;
            }

            if (charIndex < 0)
                charIndex = 0;

            return new TextPoint(charIndex, rowIndex);
        }

        /// <summary>
        /// Returns the caret's position as a Point.
        /// </summary>
        /// <returns>The caret's position as a Point.</returns>
        private Point GetCaretPixelPos()
        {
            return GetTextPointPixelPos(textEditorControl.Caret.Position);
        }

        /// <summary>
        /// Returns the Point at the given TextPoint.
        /// </summary>
        /// <param name="textPoint">TextPoint to find Point on.</param>
        /// <returns>The Point at the given TextPoint.</returns>
        private Point GetTextPointPixelPos(TextPoint textPoint)
        {
            Row row = textEditorControl.Document[textPoint.Y];

            if (row == null)
                return new Point();

            if (row.RowState == RowState.SegmentParsed)
                textEditorControl.Document.Parser.ParseLine(row.Index, true);

            Row expansionRow = null;

            if (row.IsCollapsedEndPart == true)
                expansionRow = row.ExpansionStartRow;
            else
                expansionRow = row;

            int expansionVisibleIndex = expansionRow.VisibleIndex;
            int y = (expansionVisibleIndex - textEditorControl.ViewPoint.FirstVisibleRow);

            if (y < 0 || y > textEditorControl.ViewPoint.VisibleRowCount)
                return new Point(-1, -1);

            y *= textEditorControl.ViewPoint.RowHeight;

            bool collapsed = row.IsCollapsedEndPart;
            int position = this.MeasureRow(row, textPoint.X, row.ExpansionPixelStart).Width + 1;

            if (collapsed == true)
            {
                position += row.ExpansionPixelStart;
                position -= MeasureRow(row, row.ExpansionStartChar, row.ExpansionPixelStart).Width;
            }

            int x = position + textEditorControl.ViewPoint.TextMargin - textEditorControl.ViewPoint.ClientAreaStart;
            if (x < textEditorControl.ViewPoint.TextMargin || x > textEditorControl.ViewPoint.ClientAreaWidth + textEditorControl.ViewPoint.TextMargin)
                return new Point(x, y);

            return new Point(x, y);
        }

        #endregion

        #region Protected

        /// <summary>
        /// Renders all content of the TextEditor.
        /// </summary>
        /// <param name="g">Graphics to use when rendering.</param>
        protected virtual void RenderAllBase(Graphics g)
        {
            int firstVisibleRow = textEditorControl.ViewPoint.FirstVisibleRow;
            Row row = null;

            for (int i = 0; i < textEditorControl.ViewPoint.VisibleRowCount; i++)
            {
                if (firstVisibleRow >= 0 && firstVisibleRow < textEditorControl.Document.VisibleRows.Count)
                {
                    row = textEditorControl.Document.VisibleRows[firstVisibleRow];
                    if (renderCaretRowOnly == true)
                    {
                        if (row == textEditorControl.Caret.CurrentRow)
                            this.RenderRow(g, textEditorControl.Document.IndexOf(row), i);

                        if (textEditorControl.Caret.CurrentRow.ExpansionEndSegment != null &&
                            textEditorControl.Caret.CurrentRow.ExpansionEndSegment.StartRow != null &&
                            textEditorControl.Caret.CurrentRow.ExpansionEndSegment.StartRow == row)
                        {
                            this.RenderRow(g, textEditorControl.Document.IndexOf(row), i);
                        }
                    }
                    else
                        this.RenderRow(g, textEditorControl.Document.IndexOf(row), i);
                }
                else
                {
                    if (renderCaretRowOnly == false)
                        this.RenderRow(g, textEditorControl.Document.Count, i);
                }

                firstVisibleRow++;
            }
        }

        /// <summary>
        /// Renders the row at the given index.
        /// </summary>
        /// <param name="rowIndex">Index of the row.</param>
        /// <param name="rowPosition">Position of the row.</param>
        protected virtual void RenderRow(int rowIndex, int rowPosition)
        {
            using (Graphics g = textEditorControl.CreateGraphics())
                this.RenderRow(g, rowIndex, rowPosition);
        }

        /// <summary>
        /// Renders the row at the given index.
        /// </summary>
        /// <param name="g">Graphics to use when rendering.</param>
        /// <param name="rowIndex">Index of the row.</param>
        /// <param name="rowPosition">Position of the row.</param>
        protected virtual void RenderRow(Graphics g, int rowIndex, int rowPosition)
        {
            if (rowIndex >= 0 && rowIndex < textEditorControl.Document.Count)
            {
                if (textEditorControl.Document[rowIndex].RowState == RowState.SegmentParsed)
                {
                    textEditorControl.Document.Parser.ParseLine(rowIndex, true);
                    textEditorControl.Document[rowIndex].RowState = RowState.AllParsed;
                }
            }

            GDISurface backBuffer = renderItems.BackBuffer;
            bool foundColor = false;

            GDIBrush backgroundBrush = renderItems.BackgroundBrush;
            if (rowIndex < textEditorControl.Document.Count && rowIndex >= 0)
            {
                Row row = textEditorControl.Document[rowIndex];
                if (spanFound && rowIndex >= firstSpanRow && rowIndex <= lastSpanRow &&
                    textEditorControl.TextEditor.ScopeBackColor != Color.Transparent)
                {
                    backgroundBrush = new GDIBrush(textEditorControl.TextEditor.ScopeBackColor);
                    foundColor = true;
                }
                else if (row.BackColor != Color.Transparent)
                {
                    backgroundBrush = new GDIBrush(row.BackColor);
                    foundColor = true;
                }
                else
                {
                    if (row.EndSegment != null)
                    {
                        Segment endSegment = row.ExpansionEndSegment;
                        while (endSegment != null)
                        {
                            if (endSegment.Block.Transparent == false)
                            {
                                backgroundBrush = new GDIBrush(endSegment.Block.BackColor);
                                foundColor = true;

                                break;
                            }

                            endSegment = endSegment.Parent;
                        }

                        if (foundColor == false)
                        {
                            endSegment = row.EndSegment;
                            while (endSegment != null)
                            {
                                if (endSegment.Block.Transparent == false)
                                {
                                    backgroundBrush = new GDIBrush(endSegment.Block.BackColor);
                                    foundColor = true;

                                    break;
                                }

                                endSegment = endSegment.Parent;
                            }
                        }

                        if (foundColor == false)
                        {
                            endSegment = row.ExpansionEndSegment;
                            while (endSegment != null)
                            {
                                if (endSegment.Block.Transparent == false)
                                {
                                    backgroundBrush = new GDIBrush(endSegment.Block.BackColor);
                                    foundColor = true;

                                    break;
                                }

                                endSegment = endSegment.Parent;
                            }
                        }
                    }
                }
            }

            if (rowIndex == textEditorControl.Caret.Position.Y && textEditorControl.HighlightActiveLine == true)
                backBuffer.Clear(renderItems.HighlightLineBrush);
            else if (rowIndex >= 0 && rowIndex < textEditorControl.Document.Count)
            {
                if (textEditorControl.Document[rowIndex].IsCollapsed == true)
                {
                    if (textEditorControl.Document[rowIndex].ExpansionEndRow.Index == textEditorControl.Caret.Position.Y &&
                        textEditorControl.HighlightActiveLine == true)
                    {
                        backBuffer.Clear(renderItems.HighlightLineBrush);
                    }
                    else
                        backBuffer.Clear(backgroundBrush);
                }
                else
                    backBuffer.Clear(backgroundBrush);
            }
            else
                backBuffer.Clear(backgroundBrush);

            if (rowIndex <= textEditorControl.Selection.LogicalBounds.FirstRow ||
                rowIndex >= textEditorControl.Selection.LogicalBounds.LastRow)
            {
                this.RenderText(rowIndex);
            }

            if (textEditorControl.Selection.IsValid == true)
            {
                if (rowIndex >= textEditorControl.Selection.LogicalBounds.FirstRow &&
                    rowIndex <= textEditorControl.Selection.LogicalBounds.LastRow)
                {
                    if (textEditorControl.ContainsFocus == true)
                        renderItems.SelectionBuffer.Clear(textEditorControl.SelectionBackColor);
                    else
                        renderItems.SelectionBuffer.Clear(textEditorControl.InactiveSelectionBackColor);

                    this.RenderSelectedText(rowIndex);
                }
            }

            if (textEditorControl.ContainsFocus || textEditorControl.ViewPoint.Action == TextAction.DragText)
                this.RenderCaret(rowIndex, rowPosition * textEditorControl.ViewPoint.RowHeight + yOffset);

            this.RenderSelection(rowIndex);
            this.RenderMargins(rowIndex);

            if (textEditorControl.Document.Folding == true)
                this.RenderExpansion(rowIndex);

            RowPaintEventArgs e = new RowPaintEventArgs();
            Rectangle rectangle = new Rectangle(0, 0, textEditorControl.Width, textEditorControl.ViewPoint.RowHeight);

            e.Graphics = Graphics.FromHdc(backBuffer.HDC);
            e.Bounds = rectangle;
            e.Row = null;

            if (rowIndex >= 0 && rowIndex < textEditorControl.Document.Count)
                e.Row = textEditorControl.Document[rowIndex];

            textEditorControl.TextEditor.OnRenderRow(e);
            e.Graphics.Dispose();

            backBuffer.Flush();
            backBuffer.RenderToControl(0, rowPosition * textEditorControl.ViewPoint.RowHeight + yOffset);

            if (foundColor == true)
                backgroundBrush.Dispose();
        }

        /// <summary>
        /// Renders collapsed, selected text of a row.
        /// </summary>
        /// <param name="rowIndex">Index of the row.</param>
        /// <param name="x">X position to start at.</param>
        protected virtual void RenderCollapsedSelectedText(int rowIndex, int x)
        {
            GDISurface backBuffer = renderItems.SelectionBuffer;

            backBuffer.Font = renderItems.FontBold;
            backBuffer.FontTransparent = true;

            Row row = textEditorControl.Document[rowIndex];
            string collapsedText = row.CollapsedText;

            x++;

            int tabOrigin = -textEditorControl.ViewPoint.FirstVisibleColumn * textEditorControl.ViewPoint.CharWidth + textEditorControl.ViewPoint.TextMargin;
            int textWidth = renderItems.StringBuffer.DrawTabbedString(collapsedText, x + 1, 0, tabOrigin, textEditorControl.PixelTabSize).Width;
            renderItems.StringBuffer.Font = renderItems.FontNormal;
            renderItems.StringBuffer.FontTransparent = true;

            if (textEditorControl.ContainsFocus == true)
            {
                backBuffer.FillRect(textEditorControl.SelectionBackColor, x + 1, 1, textWidth, textEditorControl.ViewPoint.RowHeight - 2);
                backBuffer.DrawRect(textEditorControl.SelectionBorderColor, x, 0, textWidth, textEditorControl.ViewPoint.RowHeight);
            }
            else
            {
                backBuffer.FillRect(textEditorControl.InactiveSelectionBackColor, x + 1, 1, textWidth, textEditorControl.ViewPoint.RowHeight - 2);
                backBuffer.DrawRect(textEditorControl.SelectionBorderColor, x, 0, textWidth, textEditorControl.ViewPoint.RowHeight);
            }

            textWidth = backBuffer.DrawTabbedString(collapsedText, x + 1, 0, tabOrigin, textEditorControl.PixelTabSize).Width;

            if (row.ExpansionStartSegment.EndRow != null)
            {
                if (row.ExpansionStartSegment.EndRow.RowState == RowState.SegmentParsed)
                    textEditorControl.Document.Parser.ParseLine(row.ExpansionStartSegment.EndRow.Index, true);

                Word endWord = row.ExpansionStartSegment.EndWord;
                x += textEditorControl.ViewPoint.FirstVisibleColumn * textEditorControl.ViewPoint.CharWidth;

                row.ExpansionStartSegment.EndRow.ExpansionPixelStart = x + textWidth - textEditorControl.ViewPoint.TextMargin + 2;
                row.ExpansionPixelEnd = x - 1;

                this.RenderSelectedText(textEditorControl.Document.IndexOf(row.ExpansionStartSegment.EndRow),
                    row.ExpansionStartSegment.EndRow.ExpansionPixelStart, endWord);
            }
        }

        /// <summary>
        /// Renders collapsed text of a row.
        /// </summary>
        /// <param name="rowIndex">Index of the row.</param>
        /// <param name="x">X position to start at.</param>
        protected virtual void RenderCollapsedText(int rowIndex, int x)
        {
            GDISurface backBuffer = renderItems.BackBuffer;

            backBuffer.Font = renderItems.FontNormal;
            backBuffer.FontTransparent = true;
            backBuffer.TextForeColor = textEditorControl.OutlineColor;

            Row row = textEditorControl.Document[rowIndex];
            string collapsedText = row.CollapsedText;

            x++;

            int tabOrigin = -textEditorControl.ViewPoint.FirstVisibleColumn * textEditorControl.ViewPoint.CharWidth + textEditorControl.ViewPoint.TextMargin;
            int textWidth = renderItems.StringBuffer.DrawTabbedString(collapsedText, x + 1, 0, tabOrigin, textEditorControl.PixelTabSize).Width;
            renderItems.StringBuffer.Font = renderItems.FontBold;

            backBuffer.FillRect(renderItems.OutlineBrush, x + 0, 0, textWidth + 2, textEditorControl.ViewPoint.RowHeight);
            backBuffer.FillRect(renderItems.BackgroundBrush, x + 1, 1, textWidth, textEditorControl.ViewPoint.RowHeight - 2);
            textWidth = backBuffer.DrawTabbedString(collapsedText, x + 1, 0, tabOrigin, textEditorControl.PixelTabSize).Width;

            if (row.ExpansionStartSegment.EndRow != null)
            {
                if (row.ExpansionStartSegment.EndRow.RowState == RowState.SegmentParsed)
                    textEditorControl.Document.Parser.ParseLine(row.ExpansionStartSegment.EndRow.Index, true);

                Word endWord = row.ExpansionStartSegment.EndWord;
                x += textEditorControl.ViewPoint.FirstVisibleColumn * textEditorControl.ViewPoint.CharWidth;

                row.ExpansionStartSegment.EndRow.ExpansionPixelStart = x + textWidth - textEditorControl.ViewPoint.TextMargin + 2;
                row.ExpansionPixelEnd = x - 1;

                this.RenderText(textEditorControl.Document.IndexOf(row.ExpansionStartSegment.EndRow),
                    row.ExpansionStartSegment.EndRow.ExpansionPixelStart, endWord);
            }
        }

        /// <summary>
        /// Renders the text of the row at the given index.
        /// </summary>
        /// <param name="rowIndex">Index of the row.</param>
        protected virtual void RenderText(int rowIndex)
        {
            this.RenderText(rowIndex, 0, null);
        }

        /// <summary>
        /// Renders the text of the row at the given index.
        /// </summary>
        /// <param name="rowIndex">Index of the row.</param>
        /// <param name="xOffset">X coordinate offset to start at.</param>
        /// <param name="startWord">Starting word.</param>
        protected virtual void RenderText(int rowIndex, int xOffset, Word startWord)
        {
            GDISurface backBuffer = renderItems.BackBuffer;

            backBuffer.Font = renderItems.FontNormal;
            backBuffer.FontTransparent = true;

            bool drawBreakpoint = false;
            if (rowIndex <= textEditorControl.Document.Count - 1)
            {
                backBuffer.TextForeColor = Color.Black;
                Row row = textEditorControl.Document[rowIndex];

                int x = textEditorControl.ViewPoint.TextMargin - textEditorControl.ViewPoint.ClientAreaStart + xOffset;

                int textWidth = 0;
                int tabOrigin = -textEditorControl.ViewPoint.FirstVisibleColumn * textEditorControl.ViewPoint.CharWidth +
                    textEditorControl.ViewPoint.TextMargin;

                bool showWhitespace = textEditorControl.ShowWhitespace;
                bool startDraw = startWord == null;

                row.ExpansionStartChar = 0;
                row.ExpansionEndChar = 0;
                bool expansion = false;

                WordCollection wordCollection = row.FormattedWords;
                Word currentWord = null;

                for (int i = 0; i < wordCollection.Count; i++)
                {
                    currentWord = wordCollection[i];

                    if (startDraw == true)
                    {
                        if (currentWord.Segment == row.ExpansionStartSegment && row.ExpansionStartSegment != null)
                        {
                            if (row.ExpansionStartSegment.Expanded == false)
                            {
                                this.RenderCollapsedText(rowIndex, x);
                                expansion = true;
                                break;
                            }
                        }

                        if ((currentWord.Type == WordType.Space || currentWord.Type == WordType.Tab) && drawBreakpoint == false &&
                            textEditorControl.ShowTabGuides == true)
                        {
                            int xTabSize = x - (textEditorControl.ViewPoint.TextMargin - textEditorControl.ViewPoint.ClientAreaStart + xOffset);

                            if ((double)xTabSize / (double)textEditorControl.PixelTabSize == xTabSize / textEditorControl.PixelTabSize)
                                backBuffer.FillRect(textEditorControl.TabGuideColor, x, 0, 1, textEditorControl.ViewPoint.RowHeight);
                        }

                        if (currentWord.Type == WordType.Word || showWhitespace == false)
                        {
                            if (currentWord.Style != null)
                            {
                                this.SetFont(currentWord.Style.Bold, currentWord.Style.Italic, currentWord.Style.Underline, backBuffer);

                                backBuffer.TextBackColor = currentWord.Style.BackColor;
                                backBuffer.TextForeColor = currentWord.Style.ForeColor;
                                backBuffer.FontTransparent = currentWord.Style.Transparent;
                            }
                            else
                            {
                                backBuffer.Font = renderItems.FontNormal;
                                backBuffer.TextForeColor = Color.Black;
                                backBuffer.FontTransparent = true;
                            }

                            if (currentWord.Type == WordType.Word)
                                drawBreakpoint = true;

                            if (row.Breakpoint == true && drawBreakpoint == true)
                            {
                                backBuffer.TextForeColor = textEditorControl.BreakpointForeColor;
                                backBuffer.TextBackColor = textEditorControl.BreakpointBackColor;
                                backBuffer.FontTransparent = false;
                            }

                            if (currentWord.Segment != null && currentWord.Segment.Scope != null)
                            {
                                if (textEditorControl.BracketMatching == true && (currentWord == bracketEnd || currentWord == bracketStart))
                                {
                                    backBuffer.TextForeColor = textEditorControl.BracketForeColor;
                                    backBuffer.Font = new GDIFont(textEditorControl.FontName, textEditorControl.FontSize,
                                        textEditorControl.BracketBold, textEditorControl.BracketItalic,
                                        textEditorControl.BracketUnderline, textEditorControl.BracketStrikethrough);

                                    if (textEditorControl.BracketBackColor != Color.Transparent)
                                    {
                                        backBuffer.TextBackColor = textEditorControl.BracketBackColor;
                                        backBuffer.FontTransparent = false;
                                    }

                                    textWidth = backBuffer.DrawTabbedString(currentWord.Text, x, 0, tabOrigin, textEditorControl.PixelTabSize).Width;

                                    if (textEditorControl.BracketBorderColor != Color.Transparent)
                                    {
                                        backBuffer.DrawRect(textEditorControl.BracketBorderColor, x, 0, textWidth,
                                            textEditorControl.ViewPoint.RowHeight - 1);
                                    }
                                }
                                else
                                    textWidth = backBuffer.DrawTabbedString(currentWord.Text, x, 0, tabOrigin, textEditorControl.PixelTabSize).Width;
                            }
                            else
                                textWidth = backBuffer.DrawTabbedString(currentWord.Text, x, 0, tabOrigin, textEditorControl.PixelTabSize).Width;

                            if (currentWord.HasError == true || currentWord.HasWarning == true)
                            {
                                int lineY = textEditorControl.ViewPoint.RowHeight - 1;

                                Color color;
                                if (currentWord.HasError == true)
                                    color = currentWord.ErrorColor;
                                else
                                    color = currentWord.WarningColor;

                                for (int lineX = 0; lineX < textWidth + 3; lineX += 4)
                                {
                                    backBuffer.DrawLine(color, new Point(x + lineX, lineY), new Point(x + lineX + 2, lineY - 2));
                                    backBuffer.DrawLine(color, new Point(x + lineX + 2, lineY - 2), new Point(x + lineX + 4, lineY));
                                }
                            }
                        }
                        else if (currentWord.Type == WordType.Space && showWhitespace == true)
                        {
                            backBuffer.Font = renderItems.FontNormal;
                            backBuffer.TextForeColor = textEditorControl.WhitespaceColor;
                            backBuffer.FontTransparent = true;

                            if (row.Breakpoint == true && drawBreakpoint == true)
                            {
                                backBuffer.TextForeColor = textEditorControl.BreakpointForeColor;
                                backBuffer.TextBackColor = textEditorControl.BreakpointBackColor;
                                backBuffer.FontTransparent = false;
                            }

                            backBuffer.DrawTabbedString("·", x, 0, tabOrigin, textEditorControl.PixelTabSize);
                            textWidth = backBuffer.DrawTabbedString(currentWord.Text, x, 0, tabOrigin, textEditorControl.PixelTabSize).Width;
                        }
                        else if (currentWord.Type == WordType.Tab && showWhitespace == true)
                        {
                            backBuffer.Font = renderItems.FontNormal;
                            backBuffer.TextForeColor = textEditorControl.WhitespaceColor;
                            backBuffer.FontTransparent = true;

                            if (row.Breakpoint == true && drawBreakpoint == true)
                            {
                                backBuffer.TextForeColor = textEditorControl.BreakpointForeColor;
                                backBuffer.TextBackColor = textEditorControl.BreakpointBackColor;
                                backBuffer.FontTransparent = false;
                            }

                            backBuffer.DrawTabbedString("»", x, 0, tabOrigin, textEditorControl.PixelTabSize);
                            textWidth = backBuffer.DrawTabbedString(currentWord.Text, x, 0, tabOrigin, textEditorControl.PixelTabSize).Width;
                        }

                        if (currentWord.Pattern != null)
                        {
                            if (currentWord.Pattern.IsSeparator == true)
                            {
                                backBuffer.FillRect(textEditorControl.SeparatorColor, textEditorControl.ViewPoint.TextMargin - 4,
                                    textEditorControl.ViewPoint.RowHeight - 1, textEditorControl.ViewPoint.ClientAreaWidth, 1);
                            }
                        }

                        x += textWidth;
                    }

                    if (startDraw == false)
                        row.ExpansionStartChar += currentWord.Text.Length;

                    if (currentWord == startWord)
                        startDraw = true;

                    row.ExpansionEndChar += currentWord.Text.Length;
                }

                if (textEditorControl.TextEditor.ShowEOLMarker == true && expansion == false)
                {
                    backBuffer.Font = renderItems.FontNormal;
                    backBuffer.TextForeColor = textEditorControl.TextEditor.EOLMarkerColor;
                    backBuffer.FontTransparent = true;
                    backBuffer.DrawTabbedString("¶", x, 0, tabOrigin, textEditorControl.PixelTabSize);
                }
            }
        }

        /// <summary>
        /// Renders the selected text of the row at the given index.
        /// </summary>
        /// <param name="rowIndex">Index of the row.</param>
        protected virtual void RenderSelectedText(int rowIndex)
        {
            this.RenderSelectedText(rowIndex, 0, null);
        }

        /// <summary>
        /// Renders the selected text of the row at the given index.
        /// </summary>
        /// <param name="rowIndex">Index of the row.</param>
        /// <param name="xOffset">X coordinate offset to start at.</param>
        /// <param name="startWord">Starting word.</param>
        protected virtual void RenderSelectedText(int rowIndex, int xOffset, Word startWord)
        {
            GDISurface backBuffer = renderItems.SelectionBuffer;

            backBuffer.Font = renderItems.FontNormal;
            backBuffer.FontTransparent = true;
            backBuffer.TextForeColor = textEditorControl.ContainsFocus == true ? textEditorControl.SelectionForeColor : textEditorControl.InactiveSelectionForeColor;

            if (rowIndex <= textEditorControl.Document.Count - 1)
            {
                Row row = textEditorControl.Document[rowIndex];
                int x = textEditorControl.ViewPoint.TextMargin - textEditorControl.ViewPoint.ClientAreaStart + xOffset;

                int textWidth = 0;
                int tabOrigin = -textEditorControl.ViewPoint.FirstVisibleColumn * textEditorControl.ViewPoint.CharWidth + textEditorControl.ViewPoint.TextMargin;

                bool showWhitespace = textEditorControl.ShowWhitespace;
                bool startDraw = startWord == null;	// Fancy little trick.

                row.ExpansionStartChar = 0;
                row.ExpansionEndChar = 0;
                bool expansion = false;

                WordCollection wordCollection = row.FormattedWords;
                Word currentWord = null;

                for (int i = 0; i < wordCollection.Count; i++)
                {
                    currentWord = wordCollection[i];

                    if (startDraw == true)
                    {
                        if (currentWord.Segment == row.ExpansionStartSegment && row.ExpansionStartSegment != null)
                        {
                            if (row.ExpansionStartSegment.Expanded == false)
                            {
                                this.RenderCollapsedSelectedText(rowIndex, x);
                                expansion = true;
                                break;
                            }
                        }

                        if (currentWord.Type == WordType.Word || showWhitespace == false)
                        {
                            if (currentWord.Style != null && textEditorControl.KeepWordStyleWhenSelected == true)
                                this.SetFont(currentWord.Style.Bold, currentWord.Style.Italic, currentWord.Style.Underline, backBuffer);
                            else
                                backBuffer.Font = renderItems.FontNormal;

                            textWidth = backBuffer.DrawTabbedString(currentWord.Text, x, 0, tabOrigin, textEditorControl.PixelTabSize).Width;

                            if (currentWord.HasError == true || currentWord.HasWarning == true)
                            {
                                int lineY = textEditorControl.ViewPoint.RowHeight - 1;

                                Color color;
                                if (currentWord.HasError == true)
                                    color = currentWord.ErrorColor;
                                else
                                    color = currentWord.WarningColor;

                                for (int lineX = 0; lineX < textWidth + 3; lineX += 4)
                                {
                                    backBuffer.DrawLine(color, new Point(lineX + lineX, lineY), new Point(lineX + lineX + 2, lineY - 2));
                                    backBuffer.DrawLine(color, new Point(lineX + lineX + 2, lineY - 2), new Point(lineX + lineX + 4, lineY));
                                }
                            }
                        }
                        else if (currentWord.Type == WordType.Space && showWhitespace == true)
                        {
                            backBuffer.Font = renderItems.FontNormal;
                            backBuffer.DrawTabbedString("·", x, 0, tabOrigin, textEditorControl.PixelTabSize);
                            textWidth = backBuffer.DrawTabbedString(currentWord.Text, x, 0, tabOrigin, textEditorControl.PixelTabSize).Width;
                        }
                        else if (currentWord.Type == WordType.Tab && showWhitespace == true)
                        {
                            backBuffer.Font = renderItems.FontNormal;
                            backBuffer.DrawTabbedString("»", x, 0, tabOrigin, textEditorControl.PixelTabSize);
                            textWidth = backBuffer.DrawTabbedString(currentWord.Text, x, 0, tabOrigin, textEditorControl.PixelTabSize).Width;

                        }

                        if (currentWord.Pattern != null)
                        {
                            if (currentWord.Pattern.IsSeparator == true)
                            {
                                backBuffer.FillRect(textEditorControl.SeparatorColor, textEditorControl.ViewPoint.TextMargin - 4,
                                    textEditorControl.ViewPoint.RowHeight - 1, textEditorControl.ViewPoint.ClientAreaWidth, 1);
                            }
                        }

                        x += textWidth;
                    }

                    if (startDraw == false)
                        row.ExpansionStartChar += currentWord.Text.Length;

                    if (currentWord == startWord)
                        startDraw = true;

                    row.ExpansionEndChar += currentWord.Text.Length;
                }

                if (textEditorControl.TextEditor.ShowEOLMarker == true && expansion == false)
                {
                    backBuffer.Font = renderItems.FontNormal;
                    backBuffer.FontTransparent = true;
                    backBuffer.DrawTabbedString("¶", x, 0, tabOrigin, textEditorControl.PixelTabSize);
                }
            }
        }

        /// <summary>
        /// Renders the caret at the row at the given index.
        /// </summary>
        /// <param name="rowIndex">Index of the row.</param>
        /// <param name="y">Y coordinate position to render the caret at.</param>
        protected virtual void RenderCaret(int rowIndex, int y)
        {
            int startRow = -1;
            int caretPositionY = textEditorControl.Caret.Position.Y;

            Row row = textEditorControl.Document[caretPositionY];
            if (caretPositionY >= 0 && caretPositionY <= textEditorControl.Document.Count - 1)
            {
                if (row.ExpansionEndSegment != null)
                {
                    if (row.ExpansionEndSegment.Expanded == false)
                    {
                        row = row.ExpansionEndSegment.StartRow;
                        startRow = row.Index;
                    }
                }
            }

            bool collapsed = rowIndex == startRow;
            if (rowIndex != caretPositionY && rowIndex != startRow)
                return;

            if (textEditorControl.ViewPoint.Action == TextAction.DragText)
            {
                int position = this.MeasureRow(row, textEditorControl.Caret.Position.X).Width + 1;

                if (collapsed == true)
                {
                    position += row.ExpansionPixelStart;
                    position -= this.MeasureRow(row, row.ExpansionStartChar, row.ExpansionPixelStart).Width;
                }

                renderItems.BackBuffer.InvertRect(position + textEditorControl.ViewPoint.TextMargin - textEditorControl.ViewPoint.ClientAreaStart - 1, 0,
                    3, textEditorControl.ViewPoint.RowHeight);

                renderItems.BackBuffer.InvertRect(position + textEditorControl.ViewPoint.TextMargin - textEditorControl.ViewPoint.ClientAreaStart, 1, 1,
                    textEditorControl.ViewPoint.RowHeight - 2);
            }
            else
            {
                if (textEditorControl.OverWrite == false)
                {
                    int position = textEditorControl.ViewPoint.TextMargin - textEditorControl.ViewPoint.ClientAreaStart;
                    position += this.MeasureRow(row, textEditorControl.Caret.Position.X, row.ExpansionPixelStart).Width + 1;

                    if (collapsed == true)
                    {
                        position += row.ExpansionPixelStart;
                        position -= this.MeasureRow(row, row.ExpansionStartChar, row.ExpansionPixelStart).Width;
                    }

                    int textWidth = textEditorControl.ViewPoint.CharWidth / 12 + 1;
                    if (textWidth < 1)
                        textWidth = 1;

                    if (textEditorControl.Caret.Blink == true)
                        renderItems.BackBuffer.InvertRect(position, 0, textWidth, textEditorControl.ViewPoint.RowHeight);

                    if (textEditorControl.IMEWindow == null)
                    {
                        textEditorControl.IMEWindow = new IMEWindow(textEditorControl.Handle, textEditorControl.FontName, textEditorControl.FontSize);
                        this.InitIMEWindow();
                    }

                    textEditorControl.IMEWindow.Location = new Point(position, y);
                }
                else
                {
                    int firstPosition = this.MeasureRow(row, textEditorControl.Caret.Position.X).Width;
                    int nextPosition = this.MeasureRow(row, textEditorControl.Caret.Position.X + 1).Width;
                    int textWidth = nextPosition - firstPosition;

                    if (collapsed == true)
                    {
                        firstPosition += row.ExpansionPixelStart;
                        firstPosition -= MeasureRow(row, row.ExpansionStartChar, row.ExpansionPixelStart).Width;
                    }

                    int position = firstPosition + textEditorControl.ViewPoint.TextMargin - textEditorControl.ViewPoint.ClientAreaStart;

                    if (textEditorControl.Caret.Blink == true)
                        renderItems.BackBuffer.InvertRect(position, 0, textWidth, textEditorControl.ViewPoint.RowHeight);

                    textEditorControl.IMEWindow.Location = new Point(position, y);
                }
            }
        }

        /// <summary>
        /// Renders the margins' 'properties' (eg. line number, whether the row is bookmarked, etc.) at the row at the given index.
        /// </summary>
        /// <param name="rowIndex">Index of the row.</param>
        protected virtual void RenderMargins(int rowIndex)
        {
            GDISurface backBuffer = renderItems.BackBuffer;
            if (textEditorControl.ShowGutterMargin == true)
            {
                backBuffer.FillRect(renderItems.GutterMarginBrush, 0, 0, textEditorControl.ViewPoint.GutterMarginWidth, textEditorControl.ViewPoint.RowHeight);

                if (rowIndex <= textEditorControl.Document.Count - 1)
                {
                    Row row = textEditorControl.Document[rowIndex];
                    if (this.RenderDefaultMargins != null)
                        this.RenderDefaultMargins(textEditorControl, new RenderMarginEventArgs(row));

                    if (textEditorControl.ViewPoint.RowHeight >= textEditorControl.TextEditor.GutterIcons.ImageSize.Height)
                    {
                        if (row.Bookmarked == true)
                            textEditorControl.TextEditor.GutterIcons.Draw(Graphics.FromHdc(backBuffer.HDC), 0, 0, 1);

                        if (row.Breakpoint == true)
                            textEditorControl.TextEditor.GutterIcons.Draw(Graphics.FromHdc(backBuffer.HDC), 0, 0, 0);
                    }
                    else
                    {
                        int rowHeight = textEditorControl.ViewPoint.RowHeight;

                        if (row.Bookmarked == true)
                            textEditorControl.TextEditor.GutterIcons.Draw(Graphics.FromHdc(backBuffer.HDC), 0, 0, rowHeight, rowHeight, 1);

                        if (row.Breakpoint == true)
                            textEditorControl.TextEditor.GutterIcons.Draw(Graphics.FromHdc(backBuffer.HDC), 0, 0, rowHeight, rowHeight, 0);
                    }

                    if (row.Images != null)
                    {
                        foreach (int imageIndex in row.Images)
                        {
                            if (textEditorControl.ViewPoint.RowHeight >= textEditorControl.TextEditor.GutterIcons.ImageSize.Height)
                                textEditorControl.TextEditor.GutterIcons.Draw(Graphics.FromHdc(backBuffer.HDC), 0, 0, imageIndex);
                            else
                            {
                                int rowHeight = textEditorControl.ViewPoint.RowHeight;
                                textEditorControl.TextEditor.GutterIcons.Draw(Graphics.FromHdc(backBuffer.HDC), 0, 0, rowHeight, rowHeight, imageIndex);
                            }
                        }
                    }
                }
            }

            if (textEditorControl.ShowLineNumbers == true)
            {
                using (Graphics graphics = Graphics.FromHdc(backBuffer.HDC))
                {
                    graphics.FillRectangle(Brushes.White, new Rectangle(textEditorControl.ViewPoint.GutterMarginWidth, 0,
                        textEditorControl.ViewPoint.LineNumberMarginWidth + 1, textEditorControl.ViewPoint.RowHeight));
                }

                if (textEditorControl.UseDottedMarginBorder == true)
                {
                    for (int borderDotIndex = 0; borderDotIndex < textEditorControl.ViewPoint.RowHeight; borderDotIndex += 2)
                    {
                        backBuffer.FillRect(renderItems.LineNumberMarginBorderBrush, textEditorControl.ViewPoint.GutterMarginWidth +
                            textEditorControl.ViewPoint.LineNumberMarginWidth, borderDotIndex, 1, 1);
                    }
                }
            }

            if (textEditorControl.ShowLineNumbers == false || textEditorControl.ShowGutterMargin == false)
            {
                backBuffer.FillRect(renderItems.BackgroundBrush, textEditorControl.ViewPoint.TotalMarginWidth, 0, textEditorControl.ViewPoint.TextMargin -
                    textEditorControl.ViewPoint.TotalMarginWidth - 3, textEditorControl.ViewPoint.RowHeight);
            }
            else
            {
                backBuffer.FillRect(renderItems.BackgroundBrush, textEditorControl.ViewPoint.TotalMarginWidth + 1, 0, textEditorControl.ViewPoint.TextMargin -
                    textEditorControl.ViewPoint.TotalMarginWidth - 4, textEditorControl.ViewPoint.RowHeight);
            }

            if (textEditorControl.ShowLineNumbers == true)
            {
                backBuffer.Font = renderItems.FontNormal;
                backBuffer.FontTransparent = true;

                backBuffer.TextForeColor = textEditorControl.LineNumberForeColor;
                if (rowIndex <= textEditorControl.Document.Count - 1)
                {
                    string rowText = (rowIndex + 1).ToString(CultureInfo.InvariantCulture);
                    int rowTextWidth = this.MeasureString(rowText).Width;

                    backBuffer.DrawTabbedString(rowText, textEditorControl.ViewPoint.GutterMarginWidth + textEditorControl.ViewPoint.LineNumberMarginWidth -
                        rowTextWidth - 6, 1, 0, textEditorControl.PixelTabSize);
                }
            }
        }

        /// <summary>
        /// Renders the expansion of the row at the given index.
        /// </summary>
        /// <param name="rowIndex">Index of the row.</param>
        protected virtual void RenderExpansion(int rowIndex)
        {
            if (rowIndex <= textEditorControl.Document.Count - 1)
            {
                int startingY = 4;
                Row row = textEditorControl.Document[rowIndex];
                GDISurface backBuffer = renderItems.BackBuffer;

                if (row.Hovered == true)
                {
                    backBuffer.FillRect(renderItems.ExpansionBackgroundBrush, textEditorControl.ViewPoint.TotalMarginWidth, 0,
                        14, textEditorControl.ViewPoint.RowHeight);

                    backBuffer.FillRect(textEditorControl.RowHoverBackColor, textEditorControl.ViewPoint.TotalMarginWidth + 14, 0,
                        3, textEditorControl.ViewPoint.RowHeight);
                }

                if (row.EndSegment != null)
                {
                    if (row.ExpansionStartSegment != null && row.StartSegment.Parent == null)
                    {
                        if (row.IsCollapsed == false)
                        {
                            backBuffer.FillRect(renderItems.OutlineBrush, textEditorControl.ViewPoint.TotalMarginWidth + 6, startingY, 1,
                                textEditorControl.ViewPoint.RowHeight - startingY);
                        }
                    }
                    else if (row.EndSegment.Parent != null || row.ExpansionEndSegment != null)
                    {
                        backBuffer.FillRect(renderItems.OutlineBrush, textEditorControl.ViewPoint.TotalMarginWidth + 6,
                            0, 1, textEditorControl.ViewPoint.RowHeight);
                    }

                    if (row.ExpansionStartSegment != null)
                    {
                        GDIBrush backgroundBrush = textEditorControl.Document[rowIndex].Expanded == true ? renderItems.BackgroundBrush : renderItems.CollapsedBackgroundBrush;
                        GDIBrush symbolBrush = renderItems.SymbolBrush;

                        backBuffer.FillRect(renderItems.OutlineBrush, textEditorControl.ViewPoint.TotalMarginWidth + 2, startingY, 9, 9);
                        backBuffer.FillRect(backgroundBrush, textEditorControl.ViewPoint.TotalMarginWidth + 3, startingY + 1, 7, 7);
                        backBuffer.FillRect(symbolBrush, textEditorControl.ViewPoint.TotalMarginWidth + 4, startingY + 4, 5, 1);

                        if (row.ExpansionStartSegment.Expanded == false)
                            backBuffer.FillRect(symbolBrush, textEditorControl.ViewPoint.TotalMarginWidth + 6, startingY + 2, 1, 5);
                    }

                    if (row.ExpansionEndSegment != null)
                    {
                        backBuffer.FillRect(renderItems.OutlineBrush, textEditorControl.ViewPoint.TotalMarginWidth + 7,
                            textEditorControl.ViewPoint.RowHeight - 1, 5, 1);
                    }
                }

                if (spanFound == true && textEditorControl.TextEditor.ScopeIndicatorColor != Color.Transparent &&
                    textEditorControl.TextEditor.ShowScopeIndicator == true)
                {
                    if (rowIndex >= firstSpanRow && rowIndex <= lastSpanRow)
                    {
                        backBuffer.FillRect(textEditorControl.TextEditor.ScopeIndicatorColor, textEditorControl.ViewPoint.TotalMarginWidth + 14, 0, 2,
                            textEditorControl.ViewPoint.RowHeight);
                    }

                    if (rowIndex == firstSpanRow)
                        backBuffer.FillRect(textEditorControl.TextEditor.ScopeIndicatorColor, textEditorControl.ViewPoint.TotalMarginWidth + 14, 0, 4, 2);

                    if (rowIndex == lastSpanRow)
                    {
                        backBuffer.FillRect(textEditorControl.TextEditor.ScopeIndicatorColor, textEditorControl.ViewPoint.TotalMarginWidth + 14,
                            textEditorControl.ViewPoint.RowHeight - 2, 4, 2);
                    }
                }
            }
        }

        /// <summary>
        /// Renders the selection of the row at the given index.
        /// </summary>
        /// <param name="rowIndex">Index of the row.</param>
        protected virtual void RenderSelection(int rowIndex)
        {
            Color borderColor = textEditorControl.ContainsFocus == true ? textEditorControl.SelectionBorderColor : textEditorControl.InactiveSelectionBorderColor;

            GDISurface backBuffer = renderItems.BackBuffer;
            int borderWidth = textEditorControl.SelectionBorderColor == Color.Transparent ? 0 : 1;
            if (rowIndex <= textEditorControl.Document.Count - 1 && textEditorControl.Selection.IsValid)
            {
                Row row = textEditorControl.Document[rowIndex];
                if (row.IsCollapsed == false)
                {
                    if (rowIndex > textEditorControl.Selection.LogicalBounds.FirstRow && rowIndex < textEditorControl.Selection.LogicalBounds.LastRow)
                    {
                        int actualWidth = this.MeasureRow(row, row.Text.Length).Width + this.MeasureString("¶").Width + 3;
                        backBuffer.DrawRect(borderColor, textEditorControl.ViewPoint.TextMargin, 0, Math.Max(actualWidth -
                            textEditorControl.ViewPoint.ClientAreaStart, 0), textEditorControl.ViewPoint.RowHeight - borderWidth);

                        this.RenderRectangle(textEditorControl.ViewPoint.TextMargin + borderWidth, borderWidth, Math.Max(actualWidth -
                            textEditorControl.ViewPoint.ClientAreaStart - borderWidth, 0), textEditorControl.ViewPoint.RowHeight - (borderWidth * 2));
                    }
                    else if (rowIndex == textEditorControl.Selection.LogicalBounds.FirstRow && rowIndex == textEditorControl.Selection.LogicalBounds.LastRow)
                    {
                        int startWidth = this.MeasureRow(row, Math.Min(row.Text.Length, textEditorControl.Selection.LogicalBounds.FirstColumn)).Width;
                        int actualWidth = this.MeasureRow(row, Math.Min(row.Text.Length, textEditorControl.Selection.LogicalBounds.LastColumn)).Width - startWidth;
                        backBuffer.DrawRect(borderColor, textEditorControl.ViewPoint.TextMargin + startWidth -
                            textEditorControl.ViewPoint.ClientAreaStart, 0, actualWidth, textEditorControl.ViewPoint.RowHeight - 1);

                        this.RenderRectangle(textEditorControl.ViewPoint.TextMargin + startWidth - textEditorControl.ViewPoint.ClientAreaStart +
                            borderWidth, borderWidth, actualWidth - borderWidth, textEditorControl.ViewPoint.RowHeight - (borderWidth * 2));
                    }
                    else if (rowIndex == textEditorControl.Selection.LogicalBounds.LastRow)
                    {
                        int actualWidth = this.MeasureRow(row, Math.Min(row.Text.Length, textEditorControl.Selection.LogicalBounds.LastColumn)).Width;
                        backBuffer.DrawRect(borderColor, textEditorControl.ViewPoint.TextMargin, 0, Math.Max(actualWidth -
                            textEditorControl.ViewPoint.ClientAreaStart, 0), textEditorControl.ViewPoint.RowHeight - 1);

                        this.RenderRectangle(textEditorControl.ViewPoint.TextMargin + borderWidth, borderWidth, Math.Max(actualWidth -
                            textEditorControl.ViewPoint.ClientAreaStart - borderWidth, 0), textEditorControl.ViewPoint.RowHeight - (borderWidth * 2));
                    }
                    else if (rowIndex == textEditorControl.Selection.LogicalBounds.FirstRow)
                    {
                        int startWidth = this.MeasureRow(row, Math.Min(row.Text.Length, textEditorControl.Selection.LogicalBounds.FirstColumn)).Width;
                        int actualWidth = this.MeasureRow(row, row.Text.Length).Width + this.MeasureString("¶").Width + 3 - startWidth;
                        backBuffer.DrawRect(borderColor, textEditorControl.ViewPoint.TextMargin + startWidth -
                            textEditorControl.ViewPoint.ClientAreaStart, 0, actualWidth, textEditorControl.ViewPoint.RowHeight - borderWidth);

                        this.RenderRectangle(textEditorControl.ViewPoint.TextMargin + startWidth - textEditorControl.ViewPoint.ClientAreaStart +
                            borderWidth, borderWidth, actualWidth - borderWidth, textEditorControl.ViewPoint.RowHeight - (borderWidth * 2));
                    }
                }
                else
                {
                    this.RenderCollapsedSelection(rowIndex);
                }
            }
        }

        /// <summary>
        /// Renders the selection of the row at the given index as if it were collapsed.
        /// </summary>
        /// <param name="rowIndex">Index of the row.</param>
        protected virtual void RenderCollapsedSelection(int rowIndex)
        {
            GDISurface backBuffer = renderItems.BackBuffer;
            Row row = textEditorControl.Document[rowIndex];
            if (rowIndex > textEditorControl.Selection.LogicalBounds.FirstRow && rowIndex < textEditorControl.Selection.LogicalBounds.LastRow)
            {
                int actualWidth = this.MeasureRow(row, row.ExpansionEndChar).Width;
                this.RenderRectangle(textEditorControl.ViewPoint.TextMargin + 1, 1, Math.Max(actualWidth - textEditorControl.ViewPoint.ClientAreaStart - 1, 0),
                    textEditorControl.ViewPoint.RowHeight - 1);

                backBuffer.DrawRect(textEditorControl.OutlineColor, textEditorControl.ViewPoint.TextMargin, 0, Math.Max(actualWidth - textEditorControl.ViewPoint.ClientAreaStart, 0),
                    textEditorControl.ViewPoint.RowHeight);
            }
            else if (rowIndex == textEditorControl.Selection.LogicalBounds.FirstRow && rowIndex == textEditorControl.Selection.LogicalBounds.LastRow)
            {
                int startWidth = this.MeasureRow(row, (int)Math.Min(row.Text.Length, textEditorControl.Selection.LogicalBounds.FirstColumn)).Width;
                int minimumLength = Math.Min(row.Text.Length, textEditorControl.Selection.LogicalBounds.LastColumn);
                minimumLength = Math.Min(minimumLength, row.ExpansionEndChar);

                int actualWidth = this.MeasureRow(row, minimumLength).Width - startWidth;
                this.RenderRectangle(textEditorControl.ViewPoint.TextMargin + startWidth - textEditorControl.ViewPoint.ClientAreaStart + 1, 1, actualWidth - 1,
                    textEditorControl.ViewPoint.RowHeight - 1);

                backBuffer.DrawRect(textEditorControl.OutlineColor, textEditorControl.ViewPoint.TextMargin + startWidth -
                    textEditorControl.ViewPoint.ClientAreaStart, 0, actualWidth, textEditorControl.ViewPoint.RowHeight);
            }
            else if (rowIndex == textEditorControl.Selection.LogicalBounds.LastRow)
            {
                int actualWidth = this.MeasureRow(row, (int)Math.Min(row.Text.Length, textEditorControl.Selection.LogicalBounds.LastColumn)).Width;
                this.RenderRectangle(textEditorControl.ViewPoint.TextMargin + 1, 1, Math.Max(actualWidth - textEditorControl.ViewPoint.ClientAreaStart - 1, 0),
                    textEditorControl.ViewPoint.RowHeight - 1);

                backBuffer.DrawRect(textEditorControl.OutlineColor, textEditorControl.ViewPoint.TextMargin, 0, Math.Max(actualWidth -
                    textEditorControl.ViewPoint.ClientAreaStart, 0), textEditorControl.ViewPoint.RowHeight);
            }
            else if (rowIndex == textEditorControl.Selection.LogicalBounds.FirstRow)
            {
                int startWidth = this.MeasureRow(row, (int)Math.Min(row.Text.Length, textEditorControl.Selection.LogicalBounds.FirstColumn)).Width;
                int actualWidth = this.MeasureRow(row, (int)Math.Min(row.Text.Length, row.ExpansionEndChar)).Width - startWidth;
                this.RenderRectangle(textEditorControl.ViewPoint.TextMargin + startWidth - textEditorControl.ViewPoint.ClientAreaStart + 1, 1, actualWidth - 1,
                    textEditorControl.ViewPoint.RowHeight - 1);

                backBuffer.DrawRect(textEditorControl.OutlineColor, textEditorControl.ViewPoint.TextMargin + startWidth -
                    textEditorControl.ViewPoint.ClientAreaStart, 0, actualWidth, textEditorControl.ViewPoint.RowHeight);
            }

            if (textEditorControl.Selection.LogicalBounds.LastRow > rowIndex && textEditorControl.Selection.LogicalBounds.FirstRow <= rowIndex)
            {
                int startPixel = row.ExpansionPixelEnd;
                int endPixel = row.ExpansionEndRow.ExpansionPixelStart - startPixel + textEditorControl.ViewPoint.TextMargin;

                this.RenderRectangle(startPixel - textEditorControl.ViewPoint.ClientAreaStart + 1, 1, endPixel - 1, textEditorControl.ViewPoint.RowHeight - 2);
                backBuffer.DrawRect(textEditorControl.OutlineColor, startPixel - textEditorControl.ViewPoint.ClientAreaStart, 0, endPixel,
                    textEditorControl.ViewPoint.RowHeight);
            }

            rowIndex = row.ExpansionEndRow.Index;
            row = row.ExpansionEndRow;

            if (textEditorControl.Selection.LogicalBounds.FirstRow <= rowIndex && textEditorControl.Selection.LogicalBounds.LastRow >= rowIndex)
            {
                int endCharIndex = 0;

                if (textEditorControl.Selection.LogicalBounds.LastRow == rowIndex)
                    endCharIndex = Math.Min(textEditorControl.Selection.LogicalBounds.LastColumn, row.Text.Length);
                else
                    endCharIndex = row.Text.Length;

                int startPixel = 0;
                int endPixel = this.MeasureRow(row, endCharIndex, row.ExpansionPixelStart).Width;

                endPixel += row.ExpansionPixelStart;
                endPixel -= this.MeasureRow(row, row.ExpansionStartChar, row.ExpansionPixelStart).Width;

                if (textEditorControl.Selection.LogicalBounds.FirstRow == rowIndex)
                {
                    int startchar = Math.Max(textEditorControl.Selection.LogicalBounds.FirstColumn, row.ExpansionStartChar);
                    startPixel = this.MeasureRow(row, startchar, row.ExpansionPixelStart).Width;

                    startPixel += row.ExpansionPixelStart;
                    startPixel -= this.MeasureRow(row, row.ExpansionStartChar, row.ExpansionPixelStart).Width;
                }
                else
                {
                    startPixel = this.MeasureRow(row, row.ExpansionStartChar, row.ExpansionPixelStart).Width;

                    startPixel += row.ExpansionPixelStart;
                    startPixel -= this.MeasureRow(row, row.ExpansionStartChar, row.ExpansionPixelStart).Width;
                }

                endPixel -= startPixel;
                if (textEditorControl.Selection.LogicalBounds.LastRow != rowIndex)
                    endPixel += 6;

                this.RenderRectangle(textEditorControl.ViewPoint.TextMargin + startPixel - textEditorControl.ViewPoint.ClientAreaStart, 0, endPixel,
                    textEditorControl.ViewPoint.RowHeight);
            }
        }

        #endregion

        #endregion

        /// <summary>
        /// Initializes a new instance of DefaultPainter.
        /// </summary>
        /// <param name="control">TextEditorBase that the DefaultPainter should be drawing.</param>
        public DefaultPainter(TextEditorBase control)
        {
            textEditorControl = control;
            this.InitGraphics();
        }
    }
}
